#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include "lock_gurad.hpp"
using namespace std;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
#define NUM 5

int total_tickets = 1000;

struct thread_date {
    thread_date(const string& name, pthread_mutex_t *lock) : _thread_name(name), _lock(lock) {}
    string _thread_name;
    // 类中声明个锁
    pthread_mutex_t *_lock;
};

void *thread_start(void *args) {
    thread_date *td = static_cast<thread_date *>(args);
    const char* name = td->_thread_name.c_str();
    while(true) {
        {
            //定义局部锁
            //出了当前代码块调用析构自动解锁
            //RAII管理锁
            lock_gurad guard = &lock;
            if(total_tickets > 0) {
                usleep(1000);
                printf("%s gets a ticket, remainning tickets = %d\n", name, total_tickets);
                --total_tickets;
            }
            else {
                break;
            }
        }
    }
    printf("%s is quit\n", name);
    delete td;
    return nullptr;
}

// void *thread_start(void *args) {
//     thread_date *td = static_cast<thread_date *>(args);
//     const char* name = td->_thread_name.c_str();
//     while(true) {
//         // 加锁应该要在这个位置
//         pthread_mutex_lock(td->_lock);
//         if(total_tickets > 0) {
//             usleep(1000);
//             printf("%s gets a ticket, remainning tickets = %d\n", name, total_tickets);
//             --total_tickets;
//             pthread_mutex_unlock(td->_lock);
//         }
//         else {
//             pthread_mutex_unlock(td->_lock);
//             break;
//         }
//         // 解锁
//     }
//     printf("%s is quit\n", name);
//     delete td;
//     return nullptr;
// }

int main() {
    // 先创建一个局部互斥锁
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    vector<pthread_t> tids(NUM);
    for(int i = 0; i < NUM; i++) {
        pthread_t tid;
        // 既然要通过锁来限制多个线程
        // 那就需要让多个线程看到同一把锁，不然锁都不是同一把就没有意义了
        // 所以每个对象都包含这一把局部锁
        pthread_create(&tid, nullptr, thread_start, new thread_date("thread_name is " + to_string(i), &lock));
        tids[i] = tid;
    }
    for(pthread_t tid : tids) {
        pthread_join(tid, nullptr);
    }
    // 最后销毁互斥锁
    pthread_mutex_destroy(&lock);
    return 0;
}


// void *thread_start(void *args) {
//     thread_date *td = static_cast<thread_date *>(args);
//     const char* name = td->_thread_name.c_str();
//     while(true) {
//         // 加锁应该要在这个位置
//         pthread_mutex_lock(td->_lock);
//         if(total_tickets > 0) {
//             usleep(1000);
//             printf("%s gets a ticket, remainning tickets = %d\n", name, total_tickets);
//             --total_tickets;
//         }
//         else {
//             break;
//         }
//         // 解锁
//         pthread_mutex_unlock(td->_lock);
//     }
//     printf("%s is quit\n", name);
//     delete td;
//     return nullptr;
// }

// int total_tickets = 1000;

// struct thread_date {
//     thread_date(const string& name) : _thread_name(name) {}
//     string _thread_name;
// };

// void *thread_start(void *args) {
//     thread_date *td = static_cast<thread_date *>(args);
//     const char* name = td->_thread_name.c_str();
//     while(true) {
//         if(total_tickets > 0) {
//             usleep(1000);
//             printf("%s gets a ticket, remainning tickets = %d\n", name, total_tickets);
//             --total_tickets;
//         }
//         else {
//             break;
//         }
//     }
//     printf("%s is quit\n", name);
//     delete td;
//     return nullptr;
// }

// int main() {
//     vector<pthread_t> tids(NUM);
//     for(int i = 0; i < NUM; i++) {
//         pthread_t tid;
//         pthread_create(&tid, nullptr, thread_start, new thread_date("thread_name is " + to_string(i)));
//         tids[i] = tid;
//     }
//     for(pthread_t tid : tids) {
//         pthread_join(tid, nullptr);
//     }
//     return 0;
// }


// #define NUM 3

// __thread int g_val = 100;

// struct thread_date {
//     thread_date(const char* name) : _thread_name(name) {}
//     thread_date(const string& name) : _thread_name(name) {}
//     string _thread_name;
// };

// void *thread_start(void *args) {
//     thread_date *td = static_cast<thread_date *>(args);

//     for(int i = 0; i < NUM; ++i) {
//         printf("thread_name = %s, tid = %p, g_val = %d, &g_val = %p\n", \
//         td->_thread_name.c_str(), pthread_self(),  g_val, &g_val);
//         ++g_val;
//         sleep(1);
//     }
//     // 别忘记释放
//     delete td;
//     return nullptr;
// }

// int main() {
//     vector<pthread_t> tids(NUM);
//     for(int i = 0; i < NUM; i++) {
//         pthread_t tid;
//         pthread_create(&tid, nullptr, thread_start, new thread_date("thread_name is " + to_string(i)));
//         tids[i] = tid;
//     }
//     // for(pthread_t tid : tids) {
//     //     pthread_detach(tid);
//     // }
//     for(pthread_t tid : tids) {
//         pthread_join(tid, nullptr);
//     }
//     return 0;
// }













// #define NUM 3

// //定义全局指针获取某个线程栈区中的数据
// int *p = nullptr;

// int g_val = 100;

// struct thread_date {
//     thread_date(const char* name) : _thread_name(name) {}
//     thread_date(const string& name) : _thread_name(name) {}
//     string _thread_name;
// };

// void *thread_start(void *args) {
//     // 新线程使用主线程上开辟的堆空间
//     // 这就验证了线程们共享堆区上的数据
//     thread_date *td = static_cast<thread_date *>(args);
//     int private_v = 0;
//     if(td->_thread_name == "thread_name is 1") {
//         p = &private_v;
//     }

//     for(int i = 0; i < NUM; ++i) {
//         printf("thread_name = %s, tid = %p, private_v = %d, &private_v = %p, g_val = %d, &g_val = %p\n", \
//         td->_thread_name.c_str(), pthread_self(), private_v, &private_v, g_val, &g_val);
//         ++private_v;
//         ++g_val;
//         sleep(1);
//     }
//     // 别忘记释放
//     delete td;
//     return nullptr;
// }

// int main() {
//     // 创建多线程
//     vector<pthread_t> tids(NUM);
//     for(int i = 0; i < NUM; i++) {
//         pthread_t tid;
//         // 这里在堆上new一个对象传递给线程
//         pthread_create(&tid, nullptr, thread_start, new thread_date("thread_name is " + to_string(i)));
//         tids[i] = tid;
//     }
//     // 保证全局指针被复制
//     sleep(1);
//     // 主线程获取某个线程栈区上的数据
//     printf("*p = %d, p = %p\n", *p, p);

//     for(pthread_t tid : tids) {
//         pthread_join(tid, nullptr);
//     }
//     return 0;
// }



// //新线程执行
// void *thread_routine(void *args) {
//     int cnt = 5;
//     while(cnt ++ < 10) {
//         cout << "new thread running" << getpid() << endl;
//         sleep(1);
//     }
//     cout << "new thread quit" << endl;
//     return nullptr;
// }
// int main() {
//     //通过主线程创建新线程
//     pthread_t tid;
//     if(pthread_create(&tid, nullptr, thread_routine, nullptr) != 0) {
//         perror("pthread_create");
//         exit(-1);
//     }
//     sleep(1);
//     //若要取消一个线程则它得先存在
//     pthread_cancel(tid);
//     void* ret = nullptr;
//     if(pthread_join(tid, &ret) != 0) {
//         perror("pthread_join");
//         exit(-1);
//     }
//     cout << "main thread quit, ret = " << (long long)ret << endl;
//     return 0;
// }